//! 规则匹配器和扫描结果

use crate::event::HttpEvent;
use crate::ScanError;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt;

/// 严重程度级别
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Severity {
    /// 信息
    Info,
    /// 低危
    Low,
    /// 中危
    Medium,
    /// 高危
    High,
    /// 严重
    Critical,
}

impl fmt::Display for Severity {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Severity::Info => write!(f, "Info"),
            Severity::Low => write!(f, "Low"),
            Severity::Medium => write!(f, "Medium"),
            Severity::High => write!(f, "High"),
            Severity::Critical => write!(f, "Critical"),
        }
    }
}

impl Severity {
    /// 转换为数值
    pub fn as_number(&self) -> u8 {
        match self {
            Severity::Info => 1,
            Severity::Low => 2,
            Severity::Medium => 3,
            Severity::High => 4,
            Severity::Critical => 5,
        }
    }

    /// 从字符串解析
    pub fn from_str(s: &str) -> Self {
        match s.to_lowercase().as_str() {
            "info" | "informational" => Severity::Info,
            "low" => Severity::Low,
            "medium" | "moderate" => Severity::Medium,
            "high" => Severity::High,
            "critical" | "severe" => Severity::Critical,
            _ => Severity::Info,
        }
    }

    /// 获取颜色代码 (用于终端显示)
    pub fn color_code(&self) -> &str {
        match self {
            Severity::Info => "\x1b[36m",    // 青色
            Severity::Low => "\x1b[32m",     // 绿色
            Severity::Medium => "\x1b[33m",  // 黄色
            Severity::High => "\x1b[31m",    // 红色
            Severity::Critical => "\x1b[35m", // 紫色
        }
    }
}

/// 扫描结果
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScanResult {
    /// 结果ID
    pub id: String,
    /// 规则名称
    pub rule_name: String,
    /// 规则类型
    pub rule_type: RuleType,
    /// 严重程度
    pub severity: Severity,
    /// 标题
    pub title: String,
    /// 描述
    pub description: String,
    /// 匹配的证据
    pub evidence: Vec<String>,
    /// 影响的URL
    pub url: String,
    /// 请求方法
    pub method: Option<String>,
    /// 响应状态码
    pub status_code: Option<u16>,
    /// 响应中的匹配位置
    pub match_positions: Vec<MatchPosition>,
    /// 提取的参数
    pub extracted_params: HashMap<String, String>,
    /// 置信度 (0-100)
    pub confidence: u8,
    /// 发现时间
    pub timestamp: DateTime<Utc>,
    /// 指纹信息
    pub fingerprint: Option<String>,
    /// 标签
    pub tags: Vec<String>,
    /// 参考链接
    pub references: Vec<String>,
    /// 修复建议
    pub remediation: Option<String>,
}

impl ScanResult {
    /// 创建新的扫描结果
    pub fn new(
        rule_name: String,
        rule_type: RuleType,
        severity: Severity,
        title: String,
        url: String,
    ) -> Self {
        Self {
            id: uuid::Uuid::new_v4().to_string(),
            rule_name,
            rule_type,
            severity,
            title,
            description: String::new(),
            evidence: Vec::new(),
            url,
            method: None,
            status_code: None,
            match_positions: Vec::new(),
            extracted_params: HashMap::new(),
            confidence: 50,
            timestamp: Utc::now(),
            fingerprint: None,
            tags: Vec::new(),
            references: Vec::new(),
            remediation: None,
        }
    }

    /// 添加证据
    pub fn add_evidence(mut self, evidence: String) -> Self {
        self.evidence.push(evidence);
        self
    }

    /// 设置描述
    pub fn with_description(mut self, description: String) -> Self {
        self.description = description;
        self
    }

    /// 设置置信度
    pub fn with_confidence(mut self, confidence: u8) -> Self {
        self.confidence = confidence.min(100);
        self
    }

    /// 添加标签
    pub fn add_tag(&mut self, tag: String) {
        self.tags.push(tag);
    }

    /// 设置指纹
    pub fn with_fingerprint(mut self, fingerprint: String) -> Self {
        self.fingerprint = Some(fingerprint);
        self
    }

    /// 从HTTP事件创建结果
    pub fn from_event(event: &HttpEvent) -> Self {
        let url = format!(
            "://{}{}",
            event.metadata.host,
            event.path.as_deref().unwrap_or("/")
        );

        let mut result = Self::new(
            "unknown".to_string(),
            RuleType::Custom,
            Severity::Info,
            "Unknown detection".to_string(),
            url,
        );

        if let Some(method) = &event.method {
            result.method = Some(method.to_string());
        }

        if let Some(status) = &event.status_code {
            result.status_code = status.parse::<u16>().ok();
        }

        result
    }
}

/// 匹配位置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MatchPosition {
    /// 起始位置
    pub start: usize,
    /// 结束位置
    pub end: usize,
    /// 匹配的内容
    pub matched_text: String,
    /// 上下文 (前后各50个字符)
    pub context: String,
}

/// 规则类型
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum RuleType {
    /// Nuclei模板
    Nuclei,
    /// 自定义规则
    Custom,
    /// JavaScript规则
    JavaScript,
    /// 指纹规则
    Fingerprint,
    /// 正则规则
    Regex,
}

/// 规则匹配器接口
#[async_trait::async_trait]
pub trait RuleMatcher: Send + Sync {
    /// 匹配规则
    async fn match_rules(&self, event: &HttpEvent) -> Result<Vec<ScanResult>, ScanError>;
    /// 获取匹配器名称
    fn name(&self) -> &str;
    /// 获取规则数量
    fn rule_count(&self) -> usize;
}

/// 组合规则匹配器
pub struct CompositeMatcher {
    matchers: Vec<Box<dyn RuleMatcher>>,
}

impl CompositeMatcher {
    /// 创建新的组合匹配器
    pub fn new() -> Self {
        Self {
            matchers: Vec::new(),
        }
    }

    /// 添加匹配器
    pub fn add_matcher(mut self, matcher: Box<dyn RuleMatcher>) -> Self {
        self.matchers.push(matcher);
        self
    }

    /// 获取所有匹配器的规则数量
    pub fn total_rules(&self) -> usize {
        self.matchers.iter().map(|m| m.rule_count()).sum()
    }
}

#[async_trait::async_trait]
impl RuleMatcher for CompositeMatcher {
    async fn match_rules(&self, event: &HttpEvent) -> Result<Vec<ScanResult>, ScanError> {
        let mut all_results = Vec::new();
        
        tracing::debug!("[Vulnerability Scan] Starting rule matching for {} using {} matchers", 
                      event.metadata.host, self.matchers.len());

        for matcher in &self.matchers {
            tracing::debug!("[Vulnerability Scan] Running matcher: {} with {} rules", 
                          matcher.name(), matcher.rule_count());
            
            match matcher.match_rules(event).await {
                Ok(mut results) => {
                    // 添加匹配器名称到结果中
                    for result in &mut results {
                        result.add_tag(format!("matcher:{}", matcher.name()));
                    }
                    
                    tracing::debug!("[Vulnerability Scan] Matcher {} found {} results", 
                                  matcher.name(), results.len());
                    all_results.append(&mut results);
                }
                Err(e) => {
                    tracing::error!("[Vulnerability Scan] Error in matcher {}: {}", matcher.name(), e);
                    // 继续处理其他匹配器
                }
            }
        }
        
        tracing::debug!("[Vulnerability Scan] Completed rule matching for {}, total results: {}", 
                      event.metadata.host, all_results.len());

        Ok(all_results)
    }

    fn name(&self) -> &str {
        "composite"
    }

    fn rule_count(&self) -> usize {
        self.total_rules()
    }
}

/// 简单正则匹配器
pub struct RegexMatcher {
    name: String,
    rules: Vec<RegexRule>,
}

impl RegexMatcher {
    /// 创建新的正则匹配器
    pub fn new(name: String) -> Self {
        Self {
            name,
            rules: Vec::new(),
        }
    }

    /// 添加规则
    pub fn add_rule(mut self, rule: RegexRule) -> Self {
        self.rules.push(rule);
        self
    }

    /// 从配置文件创建匹配器
    pub fn from_config(name: String, config: &RegexMatcherConfig) -> Result<Self, ScanError> {
        let mut matcher = Self::new(name);

        for rule_config in &config.rules {
            let rule = RegexRule::from_config(rule_config)?;
            matcher.rules.push(rule);
        }

        Ok(matcher)
    }
}

#[async_trait::async_trait]
impl RuleMatcher for RegexMatcher {
    async fn match_rules(&self, event: &HttpEvent) -> Result<Vec<ScanResult>, ScanError> {
        let mut results = Vec::new();
        
        tracing::debug!("[Vulnerability Scan] RegexMatcher checking {} rules against {}", 
                      self.rules.len(), event.metadata.host);

        for rule in &self.rules {
            match rule.match_event(event).await {
                Ok(Some(result)) => {
                    tracing::debug!("[Vulnerability Scan] Rule '{}' matched for {}:{} with severity {}", 
                                  rule.name, event.metadata.host, event.path.as_deref().unwrap_or(""), rule.severity);
                    results.push(result);
                },
                Ok(None) => {
                    // 只在调试级别记录不匹配的情况
                    tracing::debug!("[Vulnerability Scan] Rule '{}' did not match {}", 
                                  rule.name, event.metadata.host);
                },
                Err(e) => {
                    tracing::error!("[Vulnerability Scan] Error matching rule '{}': {}", rule.name, e);
                }
            }
        }
        
        tracing::debug!("[Vulnerability Scan] RegexMatcher found {} results for {}", 
                      results.len(), event.metadata.host);

        Ok(results)
    }

    fn name(&self) -> &str {
        &self.name
    }

    fn rule_count(&self) -> usize {
        self.rules.len()
    }
}

/// 正则规则
#[derive(Debug, Clone)]
pub struct RegexRule {
    /// 规则名称
    pub name: String,
    /// 正则表达式
    pub pattern: regex::Regex,
    /// 严重程度
    pub severity: Severity,
    /// 描述
    pub description: String,
    /// 匹配目标
    pub target: MatchTarget,
    /// 标签
    pub tags: Vec<String>,
}

impl RegexRule {
    /// 匹配事件
    pub async fn match_event(&self, event: &HttpEvent) -> Result<Option<ScanResult>, ScanError> {
        tracing::debug!("[Vulnerability Scan] Matching rule '{}' against {}:{} with target {:?}", 
                      self.name, event.metadata.host, event.path.as_deref().unwrap_or(""), self.target);
        
        let content = match &self.target {
            MatchTarget::ResponseBody => {
                tracing::debug!("[Vulnerability Scan] Matching against response body");
                // 这里需要访问响应体内容，暂时使用headers作为示例
                &event.headers.iter().map(|(k, v)| format!("{}: {}", k, v)).collect::<Vec<_>>().join("\n")
            }
            MatchTarget::ResponseBodyHeaders => {
                tracing::debug!("[Vulnerability Scan] Matching against response body and headers");
                &event.headers.iter().map(|(k, v)| format!("{}: {}", k, v)).collect::<Vec<_>>().join("\n")
            }
            MatchTarget::RequestPath => {
                tracing::debug!("[Vulnerability Scan] Matching against request path");
                event.path.as_deref().unwrap_or("")
            }
            MatchTarget::RequestHeaders => {
                tracing::debug!("[Vulnerability Scan] Matching against request headers");
                &event.headers.iter().map(|(k, v)| format!("{}: {}", k, v)).collect::<Vec<_>>().join("\n")
            }
            MatchTarget::StatusCode => {
                tracing::debug!("[Vulnerability Scan] Matching against status code");
                &event.status_code.as_ref().map(|s| s.to_string()).unwrap_or_default()
            }
        };

        if let Some(mat) = self.pattern.find(content) {
            tracing::info!("[Vulnerability Scan] Pattern matched for rule '{}' on {}:{} - matched text: {}", 
                          self.name, event.metadata.host, event.path.as_deref().unwrap_or(""), 
                          if mat.as_str().len() > 100 { &mat.as_str()[0..100] } else { mat.as_str() });
            
            let mut result = ScanResult::from_event(event);
            result.rule_name = self.name.clone();
            result.rule_type = RuleType::Regex;
            result.severity = self.severity.clone();
            result.title = format!("Regex match: {}", self.name);
            result.description = self.description.clone();
            result.confidence = 80;
            result.tags.extend(self.tags.clone());

            // 添加匹配位置
            let start = mat.start();
            let end = mat.end();
            let context_start = start.saturating_sub(50);
            let context_end = (end + 50).min(content.len());

            result.match_positions.push(MatchPosition {
                start,
                end,
                matched_text: mat.as_str().to_string(),
                context: content[context_start..context_end].to_string(),
            });

            // 克隆result并添加证据，假设add_evidence返回修改后的结果
            let result_with_evidence = result.clone().add_evidence(format!("Matched pattern '{}' at position {}..{}",
                self.pattern.as_str(), start, end));

            return Ok(Some(result_with_evidence));
        }

        tracing::debug!("[Vulnerability Scan] Pattern did not match for rule '{}' on {}", 
                      self.name, event.metadata.host);
        Ok(None)
    }

    /// 从配置创建规则
    pub fn from_config(config: &RegexRuleConfig) -> Result<Self, ScanError> {
        let pattern = regex::Regex::new(&config.pattern)
            .map_err(|e| ScanError::MatcherError(format!("Invalid regex pattern: {}", e)))?;

        Ok(Self {
            name: config.name.clone(),
            pattern,
            severity: Severity::from_str(&config.severity),
            description: config.description.clone(),
            target: MatchTarget::from_str(&config.target),
            tags: config.tags.clone(),
        })
    }
}

/// 匹配目标
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum MatchTarget {
    ResponseBody,
    ResponseBodyHeaders,
    RequestPath,
    RequestHeaders,
    StatusCode,
}

impl MatchTarget {
    fn from_str(s: &str) -> Self {
        match s.to_lowercase().as_str() {
            "response_body" => MatchTarget::ResponseBody,
            "response_body_headers" => MatchTarget::ResponseBodyHeaders,
            "request_path" => MatchTarget::RequestPath,
            "request_headers" => MatchTarget::RequestHeaders,
            "status_code" => MatchTarget::StatusCode,
            _ => MatchTarget::ResponseBody,
        }
    }
}

/// 正则匹配器配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RegexMatcherConfig {
    pub name: String,
    pub rules: Vec<RegexRuleConfig>,
}

/// 正则规则配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RegexRuleConfig {
    pub name: String,
    pub pattern: String,
    pub severity: String,
    pub description: String,
    pub target: String,
    pub tags: Vec<String>,
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::event::{HttpEvent, EventType};
    use http::{Method, StatusCode, Uri};
    use std::collections::HashMap;

    #[tokio::test]
    async fn test_regex_matcher() {
        let rule = RegexRule::from_config(&RegexRuleConfig {
            name: "test_rule".to_string(),
            pattern: r"password|secret".to_string(),
            severity: "medium".to_string(),
            description: "Test rule for sensitive data".to_string(),
            target: "request_headers".to_string(),
            tags: vec!["test".to_string(), "sensitive".to_string()],
        }).unwrap();

        let mut headers = HashMap::new();
        headers.insert("authorization".to_string(), "Bearer secret_token".to_string());

        let event = HttpEvent::new_request(
            Method::POST,
            "https://example.com/login".parse::<Uri>().unwrap(),
            headers,
            b"username=test&password=123456",
            "127.0.0.1".to_string(),
            "conn-123".to_string(),
        );

        let result = rule.match_event(&event).await.unwrap();
        assert!(result.is_some());

        let scan_result = result.unwrap();
        assert_eq!(scan_result.rule_name, "test_rule");
        assert_eq!(scan_result.severity, Severity::Medium);
        assert!(!scan_result.match_positions.is_empty());
    }
}